package com.minisoft.gateway;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.minisoft.utils.HttpClientService;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public class AutoAuthorization {

    private static final HttpClientService httpClient = new HttpClientService();

    /**
     * 主要替换下面4个变量
     */
    private static String PROFILE = "dev";//dev/test/pre/pro
    private static final String COOKIE = "JSESSIONID=OTdhOWNlNGQtNzJhNi00ZDc1LWEzNjgtMzM4MzA3NTk2Zjlm";
//    private static String APPID = "gf-rs-rushi";
//    private static String APPID = "marketing";
    private static String APPID = "huafa-market";
//    private static String APPID = "gfcommu-dev";
//    private static String SERVICEID = "gf-interaction-center-service";
//    private static String SERVICEID = "gf-interaction-center-service-test";
//    private static String SERVICEID = "gf-interaction-center-service-pre";
//    private static String SERVICEID = "gf-interaction-center-service";
//    private static String SERVICEID = "gf-customer-center-service";
//    private static String SERVICEID = "gf-customer-center-service-test";
//    private static String SERVICEID = "gf-customer-center-service-pre";
//    private static String SERVICEID = "gf-customer-center-service-pro";
//    private static String SERVICEID = "gf-market-permit-service";
//    private static String SERVICEID = "gf-market-permit-service-test";
//    private static String SERVICEID = "gf-market-permit-service-pre";
//    private static String SERVICEID = "gf-market-permit-service";
    private static String SERVICEID = "gf-cnhuafas-customer-pool";
//    private static String SERVICEID = "gf-cnhuafas-customer-pool-test";
//    private static String SERVICEID = "gf-cnhuafas-customer-pool-pre";
//    private static String SERVICEID = "gf-cnhuafas-customer-pool-pro";
//    private static String SERVICEID = "gf-base-auth-service-pre";
//    private static String SERVICEID = "gf-base-auth-service-pro";
//    private static String SERVICEID = "gf-activity-service";
//    private static String SERVICEID = "gf-activity-service-test";

    static Map<String, String> HOST_MAP = new HashMap<>();
    static Map<String, String> SERVICE_MAP = new HashMap<>();
    static Map<String, String> APPID_MAP = new HashMap<>();
    private static final String GET_AUTHORIZED_API_LIST_PATH = "/privilege/getApiListByApp";
    private static final String GET_SERVICE_API_LIST_PATH = "/gateway/api/getListByApplicationSelected";
    private static final String AUTHORIZE_APIS_PATH = "/privilege/updateList";
    private static final String CREATE_API_PATH = "/gateway/api/create";

    static {
        HOST_MAP.put("dev", "http://apiadmin.paasdev.huafagroup.com");
        HOST_MAP.put("test", "http://apiadmin.paasdev4.huafagroup.com");
        HOST_MAP.put("pre", "http://apiadmin.paas4.huafagroup.com");
        HOST_MAP.put("pro", "http://apiadmin.paas.huafagroup.com");
        //huafa_zyt
        APPID_MAP.put("huafa_zyt","huafa_zyt");
        APPID_MAP.put("huafa_zyt-pre","huafa_zyt_pre");
        //gf-rs-rushi
        APPID_MAP.put("gf-rs-rushi","gf-rs-rushi");
        //gf-activity-admin
        APPID_MAP.put("gf-activity-admin","gf-activity-admin");
        //gfcommu
        APPID_MAP.put("gfcommu-dev","gfcommu-dev");
        APPID_MAP.put("gfcommu-test","gfcommu-test");
        APPID_MAP.put("gfcommu-pro","gfcommu-pro");
        //gfproject
        APPID_MAP.put("gfproject-dev","gfproject-dev");
        APPID_MAP.put("gfproject-test","gfproject-test");
        APPID_MAP.put("gfproject-pre","gfproject-pre");
        APPID_MAP.put("gfproject-pro","gfproject-pro");
        //qwyx
        APPID_MAP.put("qwyx-dev","qwyx-dev");
        APPID_MAP.put("qwyx-test","qwyx-dev");
        APPID_MAP.put("qwyx-pre","qwyx-pro");
        APPID_MAP.put("qwyx-pro","qwyx-pro");

        SERVICE_MAP.put("auth-dev", "gf-base-auth-service");
        SERVICE_MAP.put("auth-test", "gf-base-auth-service-test");
        SERVICE_MAP.put("permit-dev", "gf-market-permit-service");
        SERVICE_MAP.put("permit-test", "gf-market-permit-service-test");
        SERVICE_MAP.put("config-dev", " gf-config-center-api-dev");
        SERVICE_MAP.put("config-test", " gf-config-center-api-test");
        SERVICE_MAP.put("activity-dev", "gf-activity-service");
        SERVICE_MAP.put("activity-test", "gf-activity-service-test");
        SERVICE_MAP.put("activity-pre", "gf-activity-service-pre");
        SERVICE_MAP.put("activity-pro", "gf-activity-service-pro");
        SERVICE_MAP.put("customer-dev", "gf-customer-center-service");
        SERVICE_MAP.put("customer-test", "gf-customer-center-service-test");
        SERVICE_MAP.put("customer-pre", "gf-customer-center-service-pre");
        SERVICE_MAP.put("customer-pro", "gf-customer-center-service-pro");
        SERVICE_MAP.put("pool-dev", "gf-cnhuafas-customer-pool");
        SERVICE_MAP.put("pool-test", "gf-cnhuafas-customer-pool-test");
        SERVICE_MAP.put("commission-dev", "huafa-commission-mq");
        SERVICE_MAP.put("commission-test", "huafa-commission-mq");
        SERVICE_MAP.put("commission-pre", "huafa-commission-mq-pre");
        SERVICE_MAP.put("commission-pro", "huafa-commission-mq");
        SERVICE_MAP.put("estension-admin-dev", "gf-self-estension-admin-dev");
        SERVICE_MAP.put("estension-admin-test", "gf-self-estension-admin-test");
        SERVICE_MAP.put("estension-dev", "gf-self-estension-dev");
        SERVICE_MAP.put("estension-test", "gf-self-estension-test");
        SERVICE_MAP.put("interaction-dev", "gf-interaction-center-service");
        SERVICE_MAP.put("interaction-test", "gf-interaction-center-service-test");
    }

    public static void main(String[] args) {
//        doApiAuth(readPendingApiListFromConfigFile());
        doApiJson();
    }

    private static void doApiJson() {
        // 从配置文件中读取待授权接口列表
        String apiJsonStr= FileUtil.readString(AutoAuthorization.class.getResource("/apiJson.txt"),"utf-8");
        JSONArray array = JSONUtil.parseArray(apiJsonStr);
        for (Object o : array) {
            JSONObject json = (JSONObject) o;
            String appid = json.getStr("appid");
            PROFILE = json.getStr("profile");
            JSONArray services = json.getJSONArray("services");
            //先拿对应环境的，没有则取默认的
            APPID = StrUtil.nullToDefault(APPID_MAP.get(StrUtil.format("{}-{}", appid, PROFILE)), APPID_MAP.get(appid));
            Assert.notNull(APPID);
            for (Object service : services) {
                JSONObject serviceJson = (JSONObject) service;
                Set<String> pendingApiList = serviceJson.getJSONArray("apis").stream().map(String::valueOf).map(String::toLowerCase).collect(Collectors.toSet());
                //为空的话，跳过
                if (CollUtil.isEmpty(pendingApiList)) {
                    continue;
                }
                SERVICEID = SERVICE_MAP.get(StrUtil.format("{}-{}",serviceJson.getStr("service"),PROFILE));
                Assert.notNull(SERVICEID);
                doApiAuth(pendingApiList);
            }
        }
    }

    /**
     * {
     * "isReleased": 0,
     * "rateLimitId": "",
     * "version": "",
     * "updateDate": "",
     * "isEnabled": 0,
     * "createBy": "",
     * "path": "/admin-api/v1/black-list/create",
     * "httpMethod": "post",
     * "authRequired": 0,
     * "checklistId": "",
     * "serviceId": "gf-activity-service-pro",
     * "name": "",
     * "id": "",
     * "createDate": "",
     * "updateBy": ""
     * }
     *
     * @param api
     * @param specifiedServiceApiMap
     * @return
     */
    static List<String> addedApiList = new ArrayList<>();
    public static String addApiIfNeed(String api, Map<String, List<Object>> specifiedServiceApiMap) {
        if (specifiedServiceApiMap.containsKey(api)) {
            return api;
        }
        String[] split = api.toLowerCase().split("\\s");
        if (split.length == 2) {
            api = split[1];
            if (specifiedServiceApiMap.containsKey(api)) {
                return api;
            }
            //新增接口
            // 创建 JSONObject 对象
            JSONObject requestJson = new JSONObject();
            // 设置各个属性
            requestJson.set("isReleased", 0);
            requestJson.set("rateLimitId", "");
            requestJson.set("version", "");
            requestJson.set("updateDate", "");
            requestJson.set("isEnabled", 0);
            requestJson.set("createBy", "");
            requestJson.set("path", api);
            requestJson.set("httpMethod", split[0]);
            requestJson.set("authRequired", 0);
            requestJson.set("checklistId", "");
            requestJson.set("serviceId", SERVICEID);
            requestJson.set("name", "");
            requestJson.set("id", "");
            requestJson.set("createDate", "");
            requestJson.set("updateBy", "");
            // 调用授权接口进行授权
            String url = buildUrl(CREATE_API_PATH);
            String s = httpClient.doPost(url, requestJson.toString(), getHeaders());
            specifiedServiceApiMap.put(api, ListUtil.toList(split[1]));
            addedApiList.add(api);
        }
        return api;
    }

    public static void doApiAuth(Set<String> pendingApiList) {
        if (CollUtil.isEmpty(pendingApiList)) {
            return;
        }
        // Step 1: 获取已授权接口列表
        JSONArray authorizedApiList = getAuthorizedApiList(APPID);
        log.info("{} 已授权接口列表个数：{}" , SERVICEID,authorizedApiList.size());
        //转成Map
        Map<String, Object> authorizedApiMap = authorizedApiList.stream().filter(item -> ((JSONObject)item).getStr("serviceId").equals(SERVICEID)).collect(Collectors.toMap(item -> ((JSONObject)item).getStr("path"), Function.identity(), (v1, v2) -> v1));

        // Step 2: 获取指定服务的接口列表
        JSONArray specifiedServiceApiList = getServiceApiList(APPID, SERVICEID);
        log.info("{} 服务的接口列表个数：{}" , SERVICEID,specifiedServiceApiList.size());
        //转成Map
        Map<String, List<Object>> specifiedServiceApiMap = specifiedServiceApiList.stream().collect(Collectors.groupingBy(item -> ((JSONObject) item).getStr("path")));

        //先新增接口
        for (String api : pendingApiList) {
            addApiIfNeed(api, specifiedServiceApiMap);
        }

        // Step 2: 重新获取指定服务的接口列表
        specifiedServiceApiList = getServiceApiList(APPID, SERVICEID);
        log.info("{} 服务的接口列表个数：{}" , SERVICEID,specifiedServiceApiList.size());
        //转成Map
        specifiedServiceApiMap = specifiedServiceApiList.stream().collect(Collectors.groupingBy(item -> ((JSONObject) item).getStr("path")));

        // Step 3: 读取待授权接口列表
//        Set<String> pendingApiList = readPendingApiListFromConfigFile();

        // Step 4: 判断待授权接口是否已经授权
        JSONArray unauthorizedApiList = new JSONArray();
        for (String api : pendingApiList) {
            api = addApiIfNeed(api,specifiedServiceApiMap);//正常不会新增了，只处理接口返回
            if (!authorizedApiMap.containsKey(api)) {
                if (specifiedServiceApiMap.containsKey(api)) {
                    //判断是否重复增加
                    unauthorizedApiList.addAll(specifiedServiceApiMap.get(api));
                } else {
                    log.info("待授权接口未在指定服务中：" + api);
                }
            }
        }
        if (unauthorizedApiList.size() > 0) {
            // Step 5: 调用授权接口授权
            authorizeApis(authorizedApiList, unauthorizedApiList);
        }
        log.info("{} 新增接口个数：{}" , SERVICEID,addedApiList.size());
        log.info("{} 新增授权的接口个数：{}" , SERVICEID,unauthorizedApiList.size());
    }

    private static JSONArray getAuthorizedApiList(String appId) {
        String url = buildUrl(GET_AUTHORIZED_API_LIST_PATH);
        JSONObject requestJson = new JSONObject();
        requestJson.put("appIdList", ListUtil.of(new JSONObject().put("appid", appId)));
        String s = httpClient.doPost(url, requestJson.toString(), getHeaders());
        JSONObject responseJson = JSONUtil.parseObj(s);
        JSONArray data = responseJson.getJSONArray("data");
        // 解析响应，获取已授权接口列表
        return data;
    }

    private static Map<String, String> getHeaders() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json; charset=UTF-8");
        headers.put("Cookie", COOKIE);
        return headers;
    }

    private static JSONArray getServiceApiList(String appId, String serviceId) {
        String url = buildUrl(GET_SERVICE_API_LIST_PATH);
        JSONObject requestJson = new JSONObject();
        requestJson.put("page", 1);
        requestJson.put("limit", 1500);
        requestJson.put("applicationId", appId);
        requestJson.put("serviceId", serviceId);
        String s = httpClient.doPost(url, requestJson.toString(), getHeaders());
        JSONObject responseJson = JSONUtil.parseObj(s);
        JSONArray data = responseJson.getJSONArray("data");
        // 解析 response 获取指定服务的接口列表
        return data;
    }

    private static Set<String> readPendingApiListFromConfigFile() {
        // 从配置文件中读取待授权接口列表
        List<String> pendingApiList = FileUtil.readUtf8Lines(AutoAuthorization.class.getResource("/api.txt"));
        //转成小写
        return pendingApiList.stream().map(String::toLowerCase).collect(Collectors.toSet());
    }

    private static void authorizeApis(JSONArray authorizedApiList, JSONArray unauthorizedApiList) {
        String url = buildUrl(AUTHORIZE_APIS_PATH);
        JSONObject requestJson = new JSONObject();
        // 构建授权接口参数
        JSONArray apiIdList = new JSONArray();
        apiIdList.addAll(authorizedApiList);
        apiIdList.addAll(unauthorizedApiList);
        requestJson.put("apiIdList", apiIdList);
        // 构建已授权接口列表
        requestJson.put("appIdList", ListUtil.of(new JSONObject().put("appid", APPID)));
        requestJson.put("preApiList", authorizedApiList);

        // 调用授权接口进行授权
        String s = httpClient.doPost(url, requestJson.toString(), getHeaders());
    }

    private static String buildUrl(String path) {
        return HOST_MAP.get(PROFILE) + path;
    }
}

